#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "p2p_common.h"
#include "p2p_addr.h"
#include "p2p_msg.h"
#include "p2p_topology.h"
#include "p2p_network.h"
#include "p2p_research.h"

int iterateur=0;

/***************************************************************************
creation d'un p2p_neighbor
***************************************************************************/
p2p_neighbor p2p_neighbor_create(server_params *sp, const char *node, const char *right, const char *left, const char *name) {
	p2p_neighbor retour=(p2p_neighbor)malloc(sizeof(struct p2p_neighbor_struct));
	
	iterateur++;
	retour->id=iterateur;
	strcpy(retour->adresse, node);
	strcpy(retour->left_neigh, left);
	strcpy(retour->right_neigh, right);
	strcpy(retour->name, name);
	
	retour->left=NULL;
	retour->right=NULL;
	
	return retour;
}

/***************************************************************************
initialisation de la liste des nœuds du réseau
***************************************************************************/
void p2p_network_init(server_params *sp) {
	iterateur=0;
	//soi même
	char self[P2P_NB_MAX_CARAC_ADDR];
	strcpy(self, p2p_addr_get_str(sp->p2pMyId));
	//voisin droit
	char right[P2P_NB_MAX_CARAC_ADDR];
	strcpy(right, p2p_addr_get_str(sp->neighbors.right));
	//voisin gauche
	char left[P2P_NB_MAX_CARAC_ADDR];
	strcpy(left, p2p_addr_get_str(sp->neighbors.left));
	
	sp->network.reference=p2p_neighbor_create(sp, self, right, left, sp->server_name);
	
	if ( p2p_addr_is_equal(sp->p2pMyId, sp->neighbors.left)==0 ) {
		sp->network.reference->left=NULL;
		VERBOSE(sp,GUI,"\n");
		VERBOSE(sp,GUI,"CURE::ON\n");
	} else {
		sp->network.reference->left=sp->network.reference;
		VERBOSE(sp,GUI,"\n");
		VERBOSE(sp,GUI,"CURE::OFF\n");
	}
	
	if ( p2p_addr_is_equal(sp->p2pMyId, sp->neighbors.right)==0 ) {
		sp->network.reference->right=NULL;
		VERBOSE(sp,GUI,"CURE::ON\n");
	} else {
		sp->network.reference->right=sp->network.reference;
	}
	
	sp->network.left_end=sp->network.reference;
	sp->network.right_end=sp->network.reference;
}

/***************************************************************************
Suppression d'un p2p_neighbor
***************************************************************************/
void p2p_neighbor_delete(p2p_neighbor node) {
	if (node==NULL) return;
	
	if ( node->right!=NULL ) {
		node->right->left=node->left;
	}
	if ( node->left!=NULL ) {
		node->left->right=node->right;
	}
	free(node);
}

/***************************************************************************
Suppression d'une liste chaînée vers la droite
***************************************************************************/
void p2p_list_delete(p2p_neighbor node) {
	if ( node!=NULL ) {
		p2p_list_delete(node->right);
	}
	p2p_neighbor_delete(node);
}

/***************************************************************************
Suppression des structures utilisées pour la découverte de topologie
***************************************************************************/
void p2p_network_delete(server_params *sp) {
	
	p2p_list_delete(sp->network.lonesome_nodes);
	
	//Pour supprimer la liste doublement chaînée,
	//on part de l'extrémité gauche.
	if (sp->network.reference!=NULL) {
		//On coupe d'abord le lien entre les deux extrémités s'il existe
		if (sp->network.left_end->left!=NULL) {
			sp->network.left_end->left->right=NULL;
			sp->network.left_end->left=NULL;
		}
		p2p_list_delete(sp->network.left_end);
	}
	
	sp->network.right_end=NULL;
  sp->network.left_end=NULL;
  sp->network.reference=NULL;
  sp->network.lonesome_nodes=NULL;
}

/***************************************************************************
Insertion d'un noeud dans la liste des noeuds non classés.
***************************************************************************/
void p2p_lonesome_add(server_params *sp, p2p_neighbor node) {
	p2p_neighbor curseur=sp->network.lonesome_nodes;
	
	if (curseur!=NULL) {
		//on cherche la fin de la liste, on vérifie si node n'est pas déjà présent
		while (curseur->right!=NULL) {
			if (strcmp(curseur->adresse, node->adresse)==0) {
				p2p_neighbor_delete(node);
				return;
			}
			curseur=curseur->right;
		}
		//on pointe sur le dernier noeud de la liste
		if (strcmp(curseur->adresse, node->adresse)==0) {
			p2p_neighbor_delete(node);
			return;
		}
		//on place ne nouveau noeud au bout de la liste
		curseur->right=node;
		
	} else {
		//la liste des lonesome est vide
		sp->network.lonesome_nodes=node;
	}
}

/***************************************************************************
Vérifie si un noeud est déjà présent dans le liste double chaînée
***************************************************************************/
int p2p_network_deja_present(const server_params *sp, const p2p_neighbor node) {
	p2p_neighbor curseur;

	if (sp->network.right_end==sp->network.left_end) {
		//la liste est en anneau fermé
		curseur=sp->network.reference;
		while ( (curseur->right!=sp->network.reference) && (curseur->right!=NULL) ) {
			if ( strcmp(curseur->right->adresse, node->adresse)==0 ) {
				return P2P_OK;
			}
			curseur=curseur->right;
		}
		
	} else {
		//la liste n'est pas refermée en anneau
		//parcourt à droite
		curseur=sp->network.reference;
		while (curseur!=NULL) {
			if ( strcmp(curseur->adresse, node->adresse)==0 ) {
				return P2P_OK;
			}
			curseur=curseur->right;
		}
		//parcourt à droite
		curseur=sp->network.reference;
		while (curseur!=NULL) {
			if ( strcmp(curseur->adresse, node->adresse)==0 ) {
				return P2P_OK;
			}
			curseur=curseur->left;
		}
	}
	
	return P2P_ERROR;
}

/***************************************************************************
Insertion d'un noeud dans la liste des nœuds du réseau
***************************************************************************/
int p2p_network_add(server_params *sp, p2p_neighbor node) {
	int place=P2P_ERROR;
	char tmp[P2P_NB_MAX_CARAC_ADDR];
	
	VERBOSE(sp,GUI,"\n");
	
	//on n'exécute cette fonction que si l'anneau n'est pas encore fermé
	if ( (sp->network.right_end==sp->network.left_end) && (sp->network.right_end!=sp->network.reference) ) {
		p2p_neighbor_delete(node);
		return place;
	}
	
	//on essaie de le mettre au bout à droite
	if ( strcmp(node->adresse, sp->network.right_end->right_neigh)==0 ){
		//on vérifie que l'ordre des noeuds soit le bon (right/left)
		if ( strcmp(node->left_neigh, sp->network.right_end->adresse)!=0 ) {
			//il faut échanger les adresse du droit et du gauche
			strcpy(tmp, node->left_neigh);
			strcpy(node->left_neigh, node->right_neigh);
			strcpy(node->right_neigh, tmp);
		}
		//on réorganise le réseau
		sp->network.right_end->right=node;
		node->left=sp->network.right_end;
		sp->network.right_end=node;
		place=P2P_OK;
	}
	
	//on essaie de le mettre au bout à gauche
	if ( strcmp(node->adresse, sp->network.left_end->left_neigh)==0 ){
		//on vérifie que l'ordre des noeuds soit le bon (right/left)
		if ( strcmp(node->right_neigh, sp->network.left_end->adresse)!=0 ) {
			//il faut échanger les adresse du droit et du gauche
			strcpy(tmp, node->right_neigh);
			strcpy(node->right_neigh, node->left_neigh);
			strcpy(node->left_neigh, tmp);
		}
		//on réorganise le réseau
		sp->network.left_end->left=node;
		node->right=sp->network.left_end;
		sp->network.left_end=node;
		place=P2P_OK;
	}
	
	//s'il n'est pas voisin des noeuds des bouts, 
	//on vérifie s'il a déjà été placé dans le réseau
	if (place!=P2P_OK) {
		if ( p2p_network_deja_present(sp, node)!=P2P_OK ) {
			//il n'est pas déjà présent dans la liste double chaînée, 
			//on le met en lonesome_node
			p2p_lonesome_add(sp, node);
		} else {
			//il est déjà présent dans la liste double chainée,
			//on supprime le second exemplaire
			p2p_neighbor_delete(node);
		}
	} else {
		VERBOSE(sp,GUI,"DISCOVER::NODE::%s\n",node->adresse);
	}
	
	//si le réseau est ouvert, on peut "curer"
	if (sp->network.left_end!=sp->network.right_end) {
		VERBOSE(sp,GUI,"CURE::ON\n");
	} else {
		VERBOSE(sp,GUI,"CURE::OFF\n");
	}
	
	return place;
}

/***************************************************************************
Parcourt la liste des nœuds non classés et essaie de les insérer dans la liste chaînée
***************************************************************************/
void p2p_lonesome_append(server_params *sp, p2p_neighbor *previous) {
	if (*previous!=NULL) {
		if ( (*previous)->right!=NULL ) {
			p2p_lonesome_append(sp, &(*previous)->right);
		}
		p2p_neighbor actuel=*previous;
		*previous=(*previous)->right;
		actuel->right=NULL;
		p2p_network_add(sp, actuel);
	}
}

/***************************************************************************
Appelle la fonction précédente sur la liste des nœuds solitaires
***************************************************************************/
void p2p_lonesome_procede(server_params *sp) {
	p2p_lonesome_append(sp, &sp->network.lonesome_nodes);
}

/***************************************************************************
Écrit les noeuds dans le fichier de graph
***************************************************************************/
void p2p_graph_write_nodes(server_params *sp, FILE* fd) {
	p2p_neighbor curseur;
	
	//on écrit la référence
	fprintf(fd,"\t%d [label = \"%s\\n%s\"];\n", sp->network.reference->id, sp->network.reference->name, sp->network.reference->adresse);

	if (sp->network.right_end==sp->network.left_end) {
		//la liste est en anneau fermé
		curseur=sp->network.reference;
		while ( (curseur->right!=sp->network.reference) && (curseur->right!=NULL) ) {
			fprintf(fd,"\t%d [label = \"%s\\n%s\"];\n", curseur->right->id, curseur->right->name, curseur->right->adresse);
			curseur=curseur->right;
		}
		
	} else {
		//la liste n'est pas refermée en anneau, on a des noeuds qui ne pointent vers personne
		//on ajoute sur le graph une "terre"
		fprintf(fd,"\t0 [label = \"NULL\"];\n");
		//parcourt à droite
		curseur=sp->network.reference;
		while ( (curseur!=NULL) ) {
			fprintf(fd,"\t%d [label = \"%s\\n%s\"];\n", curseur->id, curseur->name, curseur->adresse);
			curseur=curseur->right;
		}
		//parcourt à gauche
		curseur=sp->network.reference;
		while ( (curseur!=NULL) ) {
			fprintf(fd,"\t%d [label = \"%s\\n%s\"];\n", curseur->id, curseur->name, curseur->adresse);
			curseur=curseur->left;
		}
	}
	
	//on écrit aussi les noeuds qui sont perdus dans le réseau
	curseur=sp->network.lonesome_nodes;
	while (curseur!=NULL) {
		fprintf(fd,"\t%d [label = \"%s\\n%s\"];\n", curseur->id, curseur->name, curseur->adresse);
		curseur=curseur->right;
	}
}

/***************************************************************************
Écrit les liens dans le fichier de graph
***************************************************************************/
void p2p_graph_write_links(server_params *sp, FILE* fd) {
	p2p_neighbor curseur;
	
	if (sp->network.right_end==sp->network.left_end) {
		//la liste est en anneau fermé
		curseur=sp->network.reference;
		while ( (curseur->right!=sp->network.reference) && (curseur->right!=NULL) ) {
			fprintf(fd,"\t%d -> %d [label = \"d\"];\n", curseur->id, curseur->right->id);
			fprintf(fd,"\t%d -> %d [label = \"g\"];\n", curseur->right->id, curseur->id);
			curseur=curseur->right;
		}
		//pour le dernier noeud avant de revenir sur le premier noeud
		if ( curseur->right!=NULL ) {
			fprintf(fd,"\t%d -> %d [label = \"d\"];\n", curseur->id, curseur->right->id);
			fprintf(fd,"\t%d -> %d [label = \"g\"];\n", curseur->right->id, curseur->id);
		} else {
			fprintf(fd,"\t%d -> 0 [label = \"d\"];\n", curseur->id);
			fprintf(fd,"\t%d -> 0 [label = \"g\"];\n", curseur->id);
		}
		
	} else {
		//la liste n'est pas refermée en anneau, on a des noeuds qui ne pointent vers personne
		//parcourt à droite
		curseur=sp->network.reference;
		while (curseur->right!=NULL) {
			fprintf(fd,"\t%d -> %d [label = \"d\"];\n", curseur->id, curseur->right->id);
			fprintf(fd,"\t%d -> %d [label = \"g\"];\n", curseur->right->id, curseur->id);
			curseur=curseur->right;
		}
		//pour le dernier qui pointe à NULL
		fprintf(fd,"\t%d -> 0 [label = \"d\"];\n", curseur->id);
		
		//parcourt à gauche
		curseur=sp->network.reference;
		while (curseur->left!=NULL) {
			fprintf(fd,"\t%d -> %d [label = \"g\"];\n", curseur->id, curseur->left->id);
			fprintf(fd,"\t%d -> %d [label = \"d\"];\n", curseur->left->id, curseur->id);
			curseur=curseur->left;
		}
		//pour le dernier qui pointe à NULL
		fprintf(fd,"\t%d -> 0 [label = \"g\"];\n", curseur->id);
	}
}

/***************************************************************************
Crée le fichier de graph après un discover
***************************************************************************/
int p2p_graph_write(server_params *sp) {

	//Si un discover n'a pas été précédemment fait
	if ( sp->network.left_end==NULL ) {
		VERBOSE(sp,CLIENT,"Merci de commencer par faire un discover\n");
		return P2P_OK;
	}	

	FILE* fd;
	//int pidFils=0;
  
  if ((fd = fopen("./graph","w+")) == NULL) { // ouverture en lecture/écriture
  	// l'ouverture n'a pas fonctionné
    return P2P_ERROR;
  }
  
  fprintf(fd, "digraph p2p3tc {\n");
  
  //écriture des noeuds dans le fichier
  p2p_graph_write_nodes(sp, fd);
  fprintf(fd, "\n");
  //écriture des liens dans le fichier
  p2p_graph_write_links(sp, fd);
  
  fprintf(fd, "fontsize=20;\n}\n");
  
  fclose(fd);
	
	//on affiche le réseau avec dotty
	system("dotty graph&");
	//on génère l'image jpg:
	//system("dot -Tjpg -onetwork.jpg graph&");
	
	//on l'affiche avec eog (oui je sais ca buggerait sûrement sur d'autres OS)
	//system("eog network.jpg &");
	
  return P2P_OK; // tout a fonctionné
}

/***************************************************************************
Envoi d'un message P2P_NEIGHBORS_REQ
***************************************************************************/
int p2p_neighbors_req_send(server_params *sp) {
	//VERBOSE(sp,CLIENT,"-->on rentre dans la fonction p2p_neighbors_req_send\n");
	p2p_msg neigh_req_msg = p2p_msg_create();
	if (p2p_msg_init(neigh_req_msg, P2P_MSG_NEIGHBORS_REQ, P2P_MSG_TTL_MAX, 
		sp->p2pMyId, p2p_addr_broadcast()) !=P2P_OK) {
		p2p_msg_delete(neigh_req_msg);
		return P2P_ERROR;
	}
	
	//structure pour le payload du message
	unsigned char neigh_req_payload[P2P_ADDR_SIZE];
	memcpy(neigh_req_payload, sp->p2pMyId, P2P_ADDR_SIZE);
	
	//on met le payload dans le message
	p2p_msg_init_payload(neigh_req_msg, P2P_ADDR_SIZE, neigh_req_payload);
	
	//envoi du message en version de base
	p2p_msg_set_version(neigh_req_msg, 1);
	
	//avant d'envoyer le message à nos voisins, on prépare les structures 
	//pour traiter leurs réponses
	p2p_network_delete(sp);
	p2p_network_init(sp);
	
	//on envoie le message à nos 2 voisins
	if (p2p_udp_msg_sendto(sp, neigh_req_msg, sp->neighbors.left)!=P2P_OK){
		VERBOSE(sp,VPROTO,"could not send the neighbor request to the left neighbor\n");
	}
	if (p2p_udp_msg_sendto(sp, neigh_req_msg, sp->neighbors.right)!=P2P_OK){
		VERBOSE(sp,VPROTO,"could not send the neighbor request to the right neighbor\n");
	}
	//jvois pas ce qu'on pourrai mettre de plus... une charade peut-être ?  :-/
	
	p2p_msg_delete(neigh_req_msg);
	
	VERBOSE(sp,GUI,"\n");
	VERBOSE(sp,GUI,"DISCOVER::CLEAR\n");
	VERBOSE(sp,GUI,"DISCOVER::NODE::%s\n",p2p_addr_get_str(sp->p2pMyId));
	
	return P2P_OK;
}

/***************************************************************************
Reception d'un message P2P_NEIGHBORS_REQ, envoi d'un P2P_NEIGHBORS_LIST
***************************************************************************/
int p2p_neighbors_req_received(server_params *sp, p2p_msg neigh_req_msg) {
	int i;
	
	//récupération du broadcast initiator
	p2p_addr initiator = (p2p_addr)p2p_get_payload(neigh_req_msg);
	
	//on rebroadcast le message seulement si on est pas l'initiator
	if ( p2p_addr_is_equal(initiator, sp->p2pMyId)==0 ) {
		p2p_udp_msg_rebroadcast(sp, neigh_req_msg);
	}
	
	//préparation d'un message P2P_NEIGHBORS_LIST
	p2p_msg neigh_list_msg = p2p_msg_create();
	p2p_msg_init(neigh_list_msg, P2P_MSG_NEIGHBORS_LIST, P2P_MSG_TTL_ONE_HOP, sp->p2pMyId, initiator);
	//pour être compatible avec le noeud de référence
	p2p_msg_set_version(neigh_list_msg, 1);
	
	//préparation du payload
	unsigned char list_payload[4+2*P2P_ADDR_SIZE+strlen(sp->server_name)+1];//+1 pour le '\0'
	//on met le nombre de voisins, c'est à dire 2
	list_payload[0]=0x02;
	//unsigned char nb_voisins = 2;
	//memcpy(list_payload, &nb_voisins, 1);
	//on remplit 3 octets avec n'importe quoi, ils sont pas utilisés
	for (i=0; i<3; i++) list_payload[i+1]=0x00;
	
	//on récupère nos deux voisins et on les met dans le payload
	memcpy(&list_payload[4], sp->neighbors.left, 8);
	memcpy(&list_payload[12], sp->neighbors.right, 8);
	
	//on met notre nom
	memcpy(&list_payload[4+8*2], sp->server_name, strlen(sp->server_name)+1);
	
	//on met le payload dans le message
	p2p_msg_init_payload(neigh_list_msg, 4+2*P2P_ADDR_SIZE+strlen(sp->server_name)+1, list_payload);
	
	//envoi du message en udp
	p2p_udp_msg_send(sp, neigh_list_msg);
	
	p2p_msg_delete(neigh_list_msg);
	
	return P2P_OK;
}

/***************************************************************************
Reception d'un message P2P_NEIGHBORS_LIST
***************************************************************************/
int p2p_neighbors_list_received(server_params *sp, p2p_msg neigh_list_msg) {
	
	//récupération de l'adresse de l'émetteur
	char node_source[P2P_NB_MAX_CARAC_ADDR];
	strcpy(node_source, p2p_addr_get_str(p2p_msg_get_src(neigh_list_msg)));
	
	//récupération du nombre de voisins indiqués dans le message list
	unsigned char nb_neighbors = p2p_get_payload(neigh_list_msg)[0];
	if (nb_neighbors!=2) {
		fprintf(stderr, "les noeuds étant connectés à plus ou moins de deux voisins ne sont pas pris en charge\n");
		return P2P_ERROR;
	}
	//récupération voisin droit
	p2p_addr right_addr=p2p_addr_create();
	memcpy(right_addr, &p2p_get_payload(neigh_list_msg)[1+3], P2P_ADDR_SIZE);
	char right[P2P_NB_MAX_CARAC_ADDR];
	strcpy(right, p2p_addr_get_str(right_addr));
	//récupération voisin gauche
	p2p_addr left_addr=p2p_addr_create();
	memcpy(left_addr, &p2p_get_payload(neigh_list_msg)[1+3+P2P_ADDR_SIZE], P2P_ADDR_SIZE);
	char left[P2P_NB_MAX_CARAC_ADDR];
	strcpy(left, p2p_addr_get_str(left_addr));
	//récupération du nom
	char node_name[p2p_msg_get_length(neigh_list_msg)-1-4-2*P2P_ADDR_SIZE];
	strcpy(node_name, (char *)&(p2p_get_payload(neigh_list_msg)[1+3+2*P2P_ADDR_SIZE]));
	
	p2p_neighbor noeud=p2p_neighbor_create(sp, node_source, right, left, node_name);
	if (p2p_network_add(sp, noeud)==P2P_OK) {
		p2p_lonesome_procede(sp);
	}
	
	p2p_addr_delete(right_addr);
	p2p_addr_delete(left_addr);
	
	return P2P_OK;
}

/***************************************************************************
Referme l'anneau si celui-ci est mal formé
***************************************************************************/
int p2p_cure(server_params *sp) {
	
	//on ne peut pas lancer l'opération si aucun discover n'a été fait
	if ( sp->network.reference==NULL ) {
		VERBOSE(sp,CLIENT,"Une découverte de topologie est indispensable avant le CURE.\n\n");
		VERBOSE(sp,VSYSCL,"CURE aborted, no DISCOVER done\n");
		return P2P_OK;
	}
	
	//si le réseau est bien formé, on n'a pas besoin de lancer la procédure de cure
	if (sp->network.right_end==sp->network.left_end) {
		VERBOSE(sp,CLIENT,"Le réseau est bien refermé, aucune erreur détectée.\n\n");
		VERBOSE(sp,VSYSCL,"CURE aborted, the network is OK\n");
		return P2P_OK;
	}
	
	//préparation des messages link update
	p2p_msg link_msg = p2p_msg_create();
	unsigned char link_payload[P2P_ADDR_SIZE+P2P_INT_SIZE];
	
	//creation des adresses des voisins
	p2p_addr voisin_droite = p2p_addr_create();
	p2p_addr_setstr(voisin_droite, sp->network.right_end->adresse);
	p2p_addr voisin_gauche = p2p_addr_create();
	p2p_addr_setstr(voisin_gauche, sp->network.left_end->adresse);
	
	//on envoie un link update sur le noeud du bout à droite
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId, voisin_droite) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, voisin_gauche, P2P_ADDR_SIZE);
	unsigned long int type = htonl(0x0000FFFF);
	memcpy(&link_payload[P2P_ADDR_SIZE], &type, P2P_INT_SIZE);
	if (p2p_msg_init_payload(link_msg, P2P_ADDR_SIZE+P2P_INT_SIZE, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if ( p2p_addr_is_equal(sp->p2pMyId, p2p_msg_get_dst(link_msg))==0 ) {
		if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
			return P2P_ERROR;
	} else {
		p2p_addr_delete(sp->neighbors.right);
		sp->neighbors.right=p2p_addr_duplicate(voisin_gauche);
	}
	
	//on envoie un link update sur le noeud du bout à gauche
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId, voisin_gauche) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, voisin_droite, P2P_ADDR_SIZE);
	type = htonl(0xFFFF0000);
	memcpy(&link_payload[P2P_ADDR_SIZE], &type, P2P_INT_SIZE);
	if (p2p_msg_init_payload(link_msg, P2P_ADDR_SIZE+P2P_INT_SIZE, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if ( p2p_addr_is_equal(sp->p2pMyId, p2p_msg_get_dst(link_msg))==0 ) {
		if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
			return P2P_ERROR;
	} else {
		p2p_addr_delete(sp->neighbors.left);
		sp->neighbors.left=p2p_addr_duplicate(voisin_droite);
	}
	
	//libération des structures
	p2p_addr_delete(voisin_gauche);
	p2p_addr_delete(voisin_droite);
	p2p_msg_delete(link_msg);
	
	return P2P_OK;
}

/***************************************************************************
Kick un noeud de l'anneau
***************************************************************************/
int p2p_kick(server_params *sp,char *adresse_kickee) {
	
	VERBOSE(sp,VMCTNT,"Kicking Started **\n");
	
	//on teste qu'on ne s'auto-kick pas (c'est débile)
	if ( strcmp(adresse_kickee,p2p_addr_get_str(sp->p2pMyId))==0 ) {
		VERBOSE(sp,CLIENT,"C'est pas la peine de s'auto-kicker, les leaves sont fait pour ca.\n");
		VERBOSE(sp,VSYSCL,"auto kick not accepted\n");
		VERBOSE(sp,VMCTNT,"Kicking finished **\n");
		return P2P_OK;
	}
	
	//Si un discover n'a pas été précédemment fait
	if ( sp->network.left_end==NULL ) {
		VERBOSE(sp,CLIENT,"Merci de commencer par faire un discover\n");
		VERBOSE(sp,VSYSCL,"KICK aborted, no DISCOVER done\n");
		VERBOSE(sp,VMCTNT,"Kicking finished **\n");
		return P2P_OK;
	}
	
	//creation d'un noeud de parcours qui va chercher la cible.
	//on commence par la gauche
	p2p_neighbor flying_node=sp->network.left_end;
	
	while ( 1 ) {
		if ( strcmp(adresse_kickee,flying_node->adresse)==0 ) {
	 		break;
		}
		flying_node=flying_node->right;
		//on verifie qu'on ne boucle pas
		if ( (flying_node==sp->network.left_end) || (flying_node==NULL) ){
			VERBOSE(sp,CLIENT,"adresse non trouvee\n");
			VERBOSE(sp,VSYSCL,"address not found\n");
			VERBOSE(sp,VMCTNT,"** Kicking finished **\n");
			return P2P_OK;
		}
	}
	VERBOSE(sp,VSYSCL,"node found\n");
	VERBOSE(sp,CLIENT,"\nMuahaHhahahA !!\n\n");
	VERBOSE(sp,CLIENT,"noeud trouve !!\n");
	VERBOSE(sp,CLIENT,"nom      : %s\n",flying_node->name);	
	VERBOSE(sp,CLIENT,"adresse  : %s\n",flying_node->adresse);
	VERBOSE(sp,CLIENT,"droite   : %s\n",flying_node->right_neigh);
	VERBOSE(sp,CLIENT,"gauche   : %s\n\n",flying_node->left_neigh);
	
	//préparation des messages link update
	p2p_msg link_msg = p2p_msg_create();
	unsigned char link_payload[12];
	
	//creation des adresses des voisins
	p2p_addr voisin_droite = p2p_addr_create();
	p2p_addr_setstr(voisin_droite, flying_node->right_neigh);
	p2p_addr voisin_gauche = p2p_addr_create();
	p2p_addr_setstr(voisin_gauche, flying_node->left_neigh);
	p2p_addr lui_meme = p2p_addr_create();
	p2p_addr_setstr(lui_meme, flying_node->adresse);
	
	//on envoie un link update sur son voisin de droite
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId, voisin_droite) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, voisin_gauche, 8);
	unsigned long int type = htonl(0xFFFF0000);
	memcpy(&link_payload[8], &type, 4);
	if (p2p_msg_init_payload(link_msg, 12, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if ( p2p_addr_is_equal(sp->p2pMyId, p2p_msg_get_dst(link_msg))==0 ) {
		if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
			return P2P_ERROR;
/*<<<<<<< .mine
	} else { //ca veut dire que c'est moi
		p2p_addr_copy(sp->neighbors.left,voisin_gauche);
=======*/
	} else {
		p2p_addr_delete(sp->neighbors.left);
		sp->neighbors.left=p2p_addr_duplicate(voisin_gauche);
//>>>>>>> .r101
	}
	
	//on envoie un link update sur son voisin de gauche
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId, voisin_gauche) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, voisin_droite, 8);
	type = htonl(0x0000FFFF);
	memcpy(&link_payload[8], &type, 4);
	if (p2p_msg_init_payload(link_msg, 12, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if ( p2p_addr_is_equal(sp->p2pMyId, p2p_msg_get_dst(link_msg))==0 ) {
		if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
			return P2P_ERROR;
/*<<<<<<< .mine
	} else { //ca veut dire que c'est moi
		p2p_addr_copy(sp->neighbors.right,voisin_droite);
=======*/
	} else {
		p2p_addr_delete(sp->neighbors.right);
		sp->neighbors.right=p2p_addr_duplicate(voisin_droite);
//>>>>>>> .r101
	}
	
	VERBOSE(sp,VSYSCL,"ring rebuilt\n");
	
	//on lui envoie ses link update gauche
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId,lui_meme) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, lui_meme, 8);
	type = htonl(0xFFFF0000);
	memcpy(&link_payload[8], &type, 4);
	if (p2p_msg_init_payload(link_msg, 12, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
		return P2P_ERROR;
		
	//on lui envoie son link update droit
	if (p2p_msg_init(link_msg, P2P_MSG_LINK_UPDATE, P2P_MSG_TTL_ONE_HOP, 
		sp->p2pMyId,lui_meme) != P2P_OK) return P2P_ERROR;
	memcpy(link_payload, lui_meme, 8);
	type = htonl(0x0000FFFF);
	memcpy(&link_payload[8], &type, 4);
	if (p2p_msg_init_payload(link_msg, 12, link_payload) != P2P_OK) 
		return P2P_ERROR;
	//envoi du message
	if (p2p_tcp_msg_send(sp, link_msg) != P2P_OK)
		return P2P_ERROR;
	VERBOSE(sp,VSYSCL,"node isolated\n");
	
	//libération des structures
	//p2p_addr_delete(voisin_gauche);
	//p2p_addr_delete(voisin_droite);
	p2p_addr_delete(lui_meme);
	p2p_msg_delete(link_msg);
	p2p_neighbor_delete(flying_node);
	
	VERBOSE(sp,VSYSCL,"node kicked !\n");
	VERBOSE(sp,VMCTNT,"Kicking finished **\n");

  return P2P_OK; // MUAHahAhaa !! kof kof...
}
